package com.mybatis.interceptor;

import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.sql.Connection;

/**
 * @author ALIEN-ZHU
 * @since 2020-05-07
 */
@Intercepts(
        {@Signature(
                type = StatementHandler.class,
                method = "prepare",
                args = {Connection.class, Integer.class}
        )})
public class DataScopeInterceptor implements Interceptor {

    private static final Logger LOG = LoggerFactory.getLogger(DataScopeInterceptor.class);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 1.获取执行的RoutingStatementHandler
        StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
        // 2.获取MetaObject
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        // 3.获取MappedStatement, 用于判定方法上的注解
        MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        // 4.MappedStatement的ID即为Mapper方法的全路径名
        String methodId = ms.getId();
        LOG.info("mapper method: {}", methodId);

        // 5.获取Mapper的Class名称
        String clazzName = methodId.substring(0, methodId.lastIndexOf("."));
        // 6.获取拦截的方法名
        String methodName = methodId.substring(methodId.lastIndexOf(".") + 1);
        LOG.info("clazzName: {}, methodName: {}", clazzName, methodName);
        // 7.反射获取方法上的注解内容
        Method[] methods = Class.forName(clazzName).getDeclaredMethods();
        DataScope dataScope = null;
        for (Method md : methods) {
            if (methodName.equalsIgnoreCase(md.getName())) {
                dataScope = md.getAnnotation(DataScope.class);
            }
        }
        if (dataScope == null) {
            return invocation.proceed();
        }
        String type = dataScope.type();
        String column = dataScope.column();
        if (StringUtils.isAnyEmpty(type, column)) {
            return invocation.proceed();
        }
        // 8.获取原始执行的SQL
        String sql = (String) metaObject.getValue("delegate.boundSql.sql");
        sql = sql.replaceAll("\\n", "").replaceAll("\\t", "");
        LOG.info("original SQL: {}", sql);
        // 9.根据注解内容修改SQL后执行
        if ("DEPT".equals(type)) {
            String newSql = "SELECT * FROM (" + sql + ") sss WHERE sss." + column + " = 1";
            LOG.info("new SQL: {}", newSql);
            metaObject.setValue("delegate.boundSql.sql", newSql);
        }
        return invocation.proceed();
    }

}
